package com.kk.crowd.mvc.config;

import com.kk.crowd.mvc.service.AppUserDetailService;
import com.kk.crowd.mvc.service.PasswordEncoderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

// 注意！这个类一定要放在自动扫描的包下，否则所有配置都不会生效！
// 将当前类标记为配置类
@Configuration
// 启用 Web 环境下权限控制功能
@EnableWebSecurity
public class WebAppSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private AppUserDetailService userDetailService;

    @Autowired
    private PasswordEncoderService passwordEncoder;

    // 每次调用这个方法时会检查IOC容器中是否有了对应的bean，如果有就不会真正执行这个函数，因为bean默认是单例的
    // 可以使用@Scope(value="")注解控制是否单例

    // XML：<bean id="empHandler" class="com.mykk.component.EmpHandler"> <property /></bean>
   /* @Bean
    public AdminController getAdminHandler(){
        return new AdminController ();
    }*/


    @Override
    protected void configure(AuthenticationManagerBuilder builder) throws Exception {
        // 与 SpringSecurity 环境下用户登录相关

        /*builder
                .inMemoryAuthentication ()          // 内存中完成账号、密码的检查
                .withUser ("tom")         // 指定账号
                .password ("123456")                // 指定密码
                .roles ("ADMIN","学徒")             // 指定当前用户的角色
                .and ()
                .withUser ("jerry")       // 指定账号
                .password ("123456")                   // 指定密码
                .authorities ("UPDATE","内门弟子")  // 指定当前用户的权限
                ;*/

        // 注：如果没有提供角色或权限，那么会抛出异常，
        // 异常消息是 ：
        // Cannot pass a null GrantedAuthority collection。

        // SpringSecurity 的用意是：仅仅账号、密码正确还不够，
        // 还必须具备访问特定 资源的角色或权限才能够完成认证。

        // 1、装配userDetailsService对象
        // 2、在配置类中的 configure(AuthenticationManagerBuilder)方法中应用自定义密码加密规则
        builder.userDetailsService (userDetailService).passwordEncoder (passwordEncoder);
    }

    @Override
    protected void configure(HttpSecurity security) throws Exception {
        // 与 SpringSecurity 环境下请求授权相关
        security
                .authorizeRequests ( )                   // 对请求进行授权
                .antMatchers ("/index.jsp")// 针对/index.jsp进行授权
                .permitAll ( )                           // 可以无条件访问
                .antMatchers ("/layui/**") // 针对/layui目录下所有资源进行授权
                .permitAll ( )                           // 可以无条件访问
                .antMatchers ("/level1/**")// 针对/level1/**路径设置访问要求
                .hasRole ("学徒")                       // 要求用户具备“学徒”角色才可以访 问
                .antMatchers ("/level2/**") // 针对/level2/**路径设置访问要求
                .hasAuthority ("内门弟子")              // 要求用户具备“内门弟子”权限才可 以访问
                .and ( )
                .authorizeRequests ( )                   // 对请求进行授权
                .anyRequest ( )                          // 任意请求
                .authenticated ( )                       // 需要登录以后才可以访问
                .and ( )
                .formLogin ( )                           // 需要使用表单形式登录


                // 注意：设置授权信息时需要注意，
                // 范围小的放在前面、范围大的放在后面。
                // 不然的话，小 范围的设置会被大范围设置覆盖。

                // 关于loginPage()方法的特殊说明
                // 指定登录页的同时会影响到：“提交登录表单的地址”、“退出登录的地址”、“登录失败的地址”
                // /index.jsp GET - the login form 去登陆页面
                // /index.jsp POST - process the credentials and if valid authenticate the user 提交表单登录
                // /index.jsp?error GER - redirect here for failed authentication attempts 登录失败
                // /index.jsp?logout GET - redirect here after successfully logging out 退出登录
                .loginPage ("/index.jsp")               // 指定登录页面（如果没有指定会访问SpringSecurity自带的登录页）

                // loginProcessingUrl()方法指定了登录地址，就会覆盖loginPage()方法中的设置的默认值/index.jsp POST
                .loginProcessingUrl ("/security/do/login.html")  // 指定提交登录表单地址(处理地址)
                .usernameParameter ("loginAcct")        // 定制登录账号的请求参数
                .passwordParameter ("userPswd")         // 定制登录密码的请求参数
                .defaultSuccessUrl ("/main.html")       // 登录成功后前往的地址
                .and ( )
                .csrf ( )
                .disable ( )                             // 禁用CSRF功能
                .logout ( )                              // 开启退出功能
                .logoutUrl ("/do/logout.html")           // 指定处理退出请求的URL地址
                .logoutSuccessUrl ("/index.jsp")        // 退出成功后前往的地址
        ;
    }
}
